import React, { Component } from 'react';
import { Upload } from 'antd';
import SparkMD5 from 'spark-md5';
import { connect } from 'dva';

const mapStateToProps = (state: any) => ({
  shard: state?.shard,
  loading: state?.loading.models.shard,
});

class sliceUpload extends Component {
  state = {
    preUploadPercent: -1,
    fileList: [],
    uploadParams: null,
    arrayBufferData: [],
    uploading: false,
    // copyList: '',
  };
  componentDidMount() {
    this?.props?.onRef(this);
  }
  handleBeforeUpload = (file: any) => {
    const blobSlice =
      File.prototype?.slice || File.prototype?.mozSlice || File.prototype?.webkitSlice; // 兼容性的处理
    const chunkSize = 1024 * 1024 * 2; // 切片每次2M
    const chunks = Math.ceil(file.size / chunkSize);
    let currentChunk = 0; // 当前上传的chunk
    const spark = new SparkMD5.ArrayBuffer();
    const chunkFileReader = new FileReader(); // 用于计算出每个chunkMd5
    const totalFileReader = new FileReader(); // 用于计算出总文件的fileMd5
    const sufix = file.name.substr(file.name.indexOf('.'));
    const params = {
      chunks: [],
      file: {
        fileName: file.name,
        fileSize: file.size,
      },
    };
    const arrayBufferData = [];
    const { fileList } = this.state;
    const that = this;
    // 用于上传所有分片的md5信息
    // 用于存储每个chunk的arrayBuffer对象,用于分片上传使用
    totalFileReader.readAsArrayBuffer(file);
    totalFileReader.onload = function(e) {
      spark.append(e.target.result); // 对整个totalFile生成md5
      const fileMd5 = spark.end() + new Date().getTime(); // 计算整个文件的fileMd5
      params.file.fileMd5 = fileMd5;
      const { name, size, type, uid } = file;
      const obj = { name, size, type, uid, percent: 0, status: 'uploading', file, fileMd5 };
      that.setState({
        fileList: [...fileList, obj],
      });
    };
    chunkFileReader.onload = e => {
      spark.append(e.target.result); // 对每一片分片进行md5加密
      const obj = {
        // 每一个分片需要包含的信息
        chunk: currentChunk + 1, // 分片下标
        start: currentChunk * chunkSize, // 计算分片的起始位置
        end:
          (currentChunk + 1) * chunkSize >= file.size ? file.size : (currentChunk + 1) * chunkSize, // 计算分片的结束位置
        chunkMd5: spark.end(), // 分片md5值
        chunks, // 分片总数
      };
      currentChunk += 1; // 每一次分片onload,currentChunk都需要增加，以便来计算分片的次数
      params.chunks.push(obj); // 将每一块分片的arrayBuffer存储起来，用来partUpload
      const tmp = {
        chunk: obj.chunk,
        currentBuffer: e.target.result,
      };
      arrayBufferData.push(tmp);
      if (currentChunk < chunks) {
        // 当前切片总数没有达到总数时
        loadNext(); // 计算预处理进度
        // this.setState({
        //   preUploadPercent: Number(((currentChunk / chunks) * 100).toFixed(2)),
        // });
      } else {
        // 记录所有chunks的长度
        params.file.fileChunks = params.chunks.length;
        // 表示预处理结束，将上传的参数，arrayBuffer的数据存储起来
        this.setState({
          uploadParams: params,
          arrayBufferData,
          //   preUploadPercent: 100,
        });
        this.preUpload(params);
      }
    };
    function loadNext() {
      const start = currentChunk * chunkSize;
      const end = start + chunkSize >= file.size ? file.size : start + chunkSize;
      chunkFileReader.readAsArrayBuffer(blobSlice.call(file, start, end));
    }
    loadNext();
    //   备注：此方法为更改文件名  在本地调试报错了，换用下面方法。调试时不报错可以使用这种方法
    // this.setState({
    //   fileList: [new File([file], "11111" + sufix, { type: file.type })],
    // });
    // 只允许一份文件上传

    // return false;
    // this.$AntMessage.loading({ duration: 0, content: '文件上传中...' })
  };
  handleUpload = (param: any) => {
    this.handleBeforeUpload(param.file);
    // console.log(param);
  };
  // 上传前处理(第一步)
  preUpload = uploadParams => {
    // const { uploadParams } = this.state;
    const { file } = uploadParams;
    const { dispatch, bindMd5 } = this.props;
    const that = this;

    dispatch({
      type: 'shard/repetition',
      payload: uploadParams,
      callback: data => {
        if (!data.finish) {
          if (data.percent === 100) {
            this.checkUploadStatus(file.fileMd5);
          } else {
            this.setState({ uploading: true });
            this.handlePartUpload(data.chunks, file.fileMd5);
          }
        }
        // this.setState({ fileMd5: file.fileMd5 });
        // bindMd5(file.fileMd5);
        if (data.err) {
          that.errFn(data.fileMd5);
        }
      },
    });
  };
  errFn = fileMd5 => {
    const list = this?.state?.fileList.map(e => {
      if (e.fileMd5 === fileMd5) {
        e.status = 'error';
      }
      return e;
    });
    this.setState({
      fileList: list,
    });
  };
  // 分片上传(第二步)
  handlePartUpload = (uploadList, fileMd5Name) => {
    const { closeFlag = false } = this.props; // 中断上传请求
    const batchSize = 2; // 采用分治思想，每批上传的片数，越大越卡
    const total = uploadList.length; // 获得分片的总数
    const batchCount = total / batchSize; // 需要批量处理多少次
    let batchDone = 0;
    const doBatchAppend = () => {
      if (batchDone < batchCount && closeFlag) {
        const list = uploadList.slice(batchSize * batchDone, batchSize * (batchDone + 1));
        setTimeout(() => silcePart(list), 3000);
      }
    };
    const silcePart = list => {
      const {
        dispatch,
        shard: { uploadingFiles },
      } = this.props;
      const file = uploadingFiles.find(d => fileMd5Name === d.fileMd5);
      if (!file || file.status !== 0) {
        return;
      }
      batchDone += 1;
      doBatchAppend();
      list.forEach(value => {
        const { fileMd5, chunkMd5, chunk, chunks } = value;
        const formData = new FormData();
        const blob = new Blob([this.state.arrayBufferData[chunk - 1].currentBuffer], {
          type: 'application/octet-stream',
        });
        formData.append('chunk', blob, chunkMd5);
        formData.append('fileMd5', fileMd5);
        formData.append('chunkIndex', chunk);
        formData.append('chunkSum', chunks);
        dispatch({
          type: 'shard/uploadFilePart',
          payload: formData,
          callback: res => {
            if (res?.percent === 100) {
              // 调用验证api
              //   this.setState({ uploading: false });
              this.checkUploadStatus(fileMd5);
            }
            if (res.err) {
              this.errFn(fileMd5);
            } else {
              const list = this?.state?.fileList.map(e => {
                if (e.fileMd5 === fileMd5) {
                  e.percent = res?.percent;
                }
                return e;
              });
              this.setState({
                fileList: list,
              });
            }
          },
        });
      });
    };
    doBatchAppend();
  };
  checkUploadStatus = fileMd5 => {
    const { fileList } = this.state;
    const { dispatch } = this.props;
    dispatch({
      type: 'shard/merge',
      payload: {
        fileMd5,
        fileFullName: fileList.find(e => e.fileMd5 === fileMd5)?.name.split('.')[0],
      },
      callback: data => {
        if (data?.err) {
          this.errFn(fileMd5);
        } else {
          dispatch({
            type: 'shard/getUploadFile',
            payload: { fileMd5 },
            callback: res => {
              if (res.statusCode === '0') {
                fileList.find((e, i, arr) => {
                  const bool = e.fileMd5 === fileMd5;
                  if (bool) {
                    const item = { ...e, ...res?.data, status: 'done', url: res?.data?.filePath };
                    arr[i] = item;
                    this.setState({ fileList: arr });
                    const { onChange } = this.props;
                    onChange &&
                      onChange({
                        fileList: arr,
                        file: item,
                      });
                  }
                  return bool;
                });
              } else {
                this.errFn(fileMd5);
              }
            },
          });
        }
      },
    });
  };
  handleRemove = file => {
    const { fileList } = this.state;
    const { dispatch, clearMd5 } = this.props;
    const index = fileList.indexOf(file);
    const newFileList = fileList.slice();
    const fileMd5 = fileList[index]?.fileMd5;
    newFileList.splice(index, 1);

    this.setState({
      fileList: newFileList,
      preUploadPercent: -1,
    });
    if (fileMd5) {
      dispatch({
        type: 'shard/deleteFile',
        payload: fileMd5,
      }).then(() => {
        clearMd5 && clearMd5({});
      });
    }
  };
  setData = list => {
    // const list = this.props?.fileList || [];
    const { fileList } = this.state;
    const newList = [];
    // let copyList = this.state?.copyList;
    // 是否相等
    // if (copyList !== JSON.stringify(list)) {
    list.some(e => {
      const b = fileList.some((y, i, arr) => {
        const bool = y?.uid === e?.uid;
        arr[i] = { ...y, ...e };
        return bool;
      });
      if (!b) {
        newList.push(e);
      }
      return b;
    });
    //   copyList = JSON.stringify(list);
    //   this.setState({ fileList: [...fileList, ...newList] });
    // }
    this.setState({
      fileList: [...fileList, ...newList],
    });
  };
  render() {
    const { preUploadPercent, fileList, uploading } = this.state;
    const {
      disabled,
      //   shard: { uploadingFiles },
      fileMd5,
      dispatch,
      size = 'default',
    } = this.props;
    // const noShowUploadList = fileMd5 && uploadingFiles.find(d => d.fileMd5 === fileMd5 && d.status < 2);

    const uploadProp = {
      ...this.props,
      //   beforeUpload: this.handleBeforeUpload,
      customRequest: this.handleUpload,
      onRemove: this.handleRemove,
      fileList,
      //   copyList,
    };
    // if (fileMd5) {
    //   window.onbeforeunload = function(e) {
    //     if (uploading) {
    //       dispatch({
    //         type: 'shard/breakFile',
    //         payload: fileMd5,
    //       });
    //     }
    //   };
    // }
    return (
      //   <div>
      <Upload {...uploadProp}>{/* {props?.children} */}</Upload>
      //   </div>
    );
  }
}

export default connect(mapStateToProps)(sliceUpload);
